with Interfaces.C; use Interfaces.C;

with Win32;         use Win32;
with Win32.WinUser;

package body win32api_interface.Enum_Windows is
  ---------------
  --  EnumProc --
  ---------------

  function EnumWindowsProc (hwnd   : Win32.Windef.HWND;
                            lParam : Win32.LPARAM) return Win32.Bool is
    use win32api_interface.process.helper;
    nb :  Win32.INT := 0;
    class : Win32.Char_Array(title_range);
    title : Win32.Char_Array(title_range);
    hProc : Process_ID;
  begin
    nb := Win32.WinUser.GetClassName (hwnd,
                                      Win32.Addr(class),
                                      class'Length);
    if Interfaces.C.To_Ada(Interfaces.C.Char_Array(p_param.all.Class))
      = Interfaces.C.To_Ada(Interfaces.C.Char_Array(class))
    then
      hProc := Get_Window_Thread_Process_ID(hwnd);
      nb := Win32.WinUser.GetWindowText(hwnd, Win32.Addr(title), title'Length);
      if nb /= 0 and Win32.Winuser.IsWindowVisible(HWND) = Win32.TRUE
      then
        declare
          pName : Win32.CHAR_Array :=
            Win32.CHAR_Array(Interfaces.C.To_C(Get_Process_Name(hProc)));
        begin
          --Put_Line("ProcName: "&Interfaces.C.To_Ada(Interfaces.C.Char_Array(pName))&" =?= "&
          --         Interfaces.C.To_Ada(Interfaces.C.Char_Array(p_param.all.pName)));
          if Interfaces.C.To_Ada(Interfaces.C.Char_Array(pName)) =
            Interfaces.C.To_Ada(Interfaces.C.Char_Array(p_param.all.pName))
          then
            Add((Ada.Strings.Unbounded.To_Unbounded_String(
              Interfaces.C.To_Ada(Interfaces.C.Char_Array(title))), hProc));
          end if;
        end;
      end if;
    end if;
    callback_time.update;
    return Win32.TRUE;
  end EnumWindowsProc;

  -----------------------
  -- Enumerate_Windows --
  -----------------------

  function Enumerate_Windows(Class, pName : in string)
                             return result_info_array is
    use Ada.Calendar;
    res : Win32.BOOL := 0;
  begin
    p_param := new param_type;
    p_param.all := (Win32.CHAR_Array(Interfaces.C.To_C(Class)),
                    Win32.CHAR_Array(Interfaces.C.To_C(pName)));

    res := Win32.WinUser.EnumWindows(lpEnumFunc => EnumWindowsProc'Access,
                                     lParam     => Win32.LPARAM (0));
    while Ada.Calendar.Clock - callback_time.retrieve < 0.1 loop
      delay 0.1;
    end loop;

    p_param := null;
    return to_array_and_clear;
  end Enumerate_Windows;

  procedure add(inf : in result_info) is
    p : p_block;
  begin
    p := new block;
    p.all.inf := inf;
    p.all.p := list;
    list := p;
    list_n := list_n+1;
  end add;

  procedure clear is
  begin
    list := null;
    list_n := 0;
  end clear;

  function to_array_and_clear return result_info_array is
    result : result_info_array(1..list_n);
    p : p_block;
    i : integer;
  begin
    i := 1;
    p := list;
    if list /= null then
      while p.all.p /= null loop
        result(i) := p.all.inf;
        p := p.all.p;
        i := i+1;
      end loop;
      result(i) := p.all.inf;
    end if;
    clear;
    return result;
  end to_array_and_clear;

  protected body callback_time is
    procedure update is
    begin
      t := Ada.Calendar.Clock;
    end update;

    function retrieve return Ada.Calendar.Time is
    begin
      return t;
    end retrieve;
  end callback_time;
end win32api_interface.Enum_Windows;
